﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Civilisation_code.PJoueur;
using Civilisation_code.PCarte;

namespace Civilisation_code.PInterfaces_Fabrique_Unite
{
    /// <summary>
    /// Classe abstraite Etudiant
    /// </summary>
    [Serializable]
    public abstract class Etudiant : Unite
    {
        /// <summary>
        /// Coût de création d'un étudiant
        /// </summary>
        static public int cout {
            get
            {
                return 100;
            }
        }

        /// <summary>
        /// Constructeur
        /// </summary>
        /// <param name="aBase">La valeur de l'attaque de base d'un étudiant dépendant de la civilisation</param>
        /// <param name="dBase">La valeur de la défense de base d'un étudiant dépendant de la civilisation</param>
        /// <param name="mBase">La valeur du mouvement de base d'un étudiant dépendant de la civilisation</param>
        /// <param name="vMax">La valeur de la vie de base d'un étudiant dépendant de la civilisation</param>
        /// <param name="c">Case où sera situé l'unité</param>
        /// <param name="j">Joueur possédant l'unité</param>
        public Etudiant(int aBase, int dBase, int mBase, int vMax, Case c, Joueur j)
            : base(aBase, dBase, mBase, vMax, c, j)
        {
        }

        /// <summary>
        /// Déplacer l'unité vers une case envoyée en paramètre
        /// </summary>
        /// <param name="c">Case destination</param>
        /// <returns>Renvoie vrai si le déplacement a pu s'effectuer
        ///          Renvoie faux sinon</returns>
        override public bool deplacer(Case c)
        {
            //Case nulle : erreur
            if (c == null)
                return false;

            int distance = _case.calculerDistance(c);
            if (_mvt_restant >= distance)
            {
                //Case ennemie : on attaque
                if (c.Unites.Count > 0 && c.Unites[0]._joueur != _joueur)
                {
                    int resultat;
                    do
                    {
                        Console.WriteLine("Nouveau Combat");
                        resultat = attaquer(c);
                    }
                    while (resultat != 2 && c.Unites.Count > 0);

                    PPartie.Partie.INSTANCE.verifierFinPartie();

                    //Si l'unité attaquante est morte
                    if (resultat == 2)
                        return true;
                }
           
                
                //Si on arrive là, c'est soit que la case est innocupée, soit qu'on a tué les troupes ennemies en faction

                //Y a t'il un village ennemi sur la case ? Si oui on l'annexe
                if (c.Ville != null && c.Ville.Joueur != _joueur)
                {
                    //Retrait a l'ancien joueur
                    c.Ville.Joueur._villes.Remove(c.Ville);
                    //Don au nouveau
                    _joueur._villes.Add(c.Ville);
                    //Mise à jour de l'attribut
                    c.Ville.Joueur = _joueur;
                            

                    PPartie.Partie.INSTANCE.verifierFinPartie();
                }

                _actif = true;
                _mvt_restant -= distance;
                _case.retirerUnite(this);
                _case = c;
                c.Unites.Add(this);
                Case = c;
                _joueur.vueSur();
                return true;
            }

            return false;
        }

        /// <summary>
        /// Méthode permettant à un étudaint d'attaquer une case envoyée en paramètre
        /// </summary>
        /// <param name="c">Case à attaquer</param>
        /// <returns>Renvoie 1 si l'unité defensive est morte
        ///          Renvoie 2 si l'unité offensive est morte
        ///          Renvoie 3 si aucune des 2 unités ne sont mortes</returns>
        public int attaquer(Case c)
        {
			//La meilleure unité defensive est choisie
			Unite unitDef = c.meilleureUniteDefensive();
			
			int maxVie = Math.Max(_vie_restante,unitDef._vie_restante);
			//nb de tour compris entre 3 et max vie + 2
            Random random = new Random();
			int nbTour = random.Next(3, maxVie+2);
			
			//Récupération des bonus eventuels (directeur)
			//pour l'unité attaquante :
			bool bonusAttaque = _case.contientDirecteur();
			bool bonusDefense = c.contientDirecteur();
			
			//Tant qu'il reste des tours, de la vie et de la def
			if(unitDef._defense_base>0)
				while(unitDef._vie_restante >0 && _vie_restante>0 && nbTour>0)
				{
					int atk = calculerPointAttaque();
					if(bonusAttaque)
						atk = (int)(atk * 1.5);
						
					int def = unitDef.calculerPointDefense();
					if(bonusDefense)
						def = (int) (def * 1.5);

                    double ratio = ((double)Math.Min(atk, def)) / Math.Max(atk, def);
					double bonus = 1-ratio;
				
                    double chanceAtk;
                    if(atk>def)
					    chanceAtk = 0.5 - 0.5 * bonus;
                    else
                        chanceAtk = 0.5 + 0.5 * bonus;
					
					//Facultatif : les chances defenseur seront déduites des chances attaquantes (1-chances attaquantes)
					//double chanceDef = 0,5 + 0,5 * bonus;
					
					//Partie debug :
					Console.WriteLine("Nouveau tour de combat");
					Console.WriteLine("Points d'attaque "+atk+" (Vie "+_vie_restante+" / "+_vie_base+")");
                    Console.WriteLine("Points de defense " + def + " (Vie " + unitDef._vie_restante + " / " + unitDef._vie_base + ")");
                    Console.WriteLine("Ratio " + ratio);
                    Console.WriteLine("Bonus " + bonus);
					Console.WriteLine("Chances de l'attaquant "+chanceAtk);
					Console.WriteLine("Chances du defenseur "+(1-chanceAtk));			
					
					int tirage = random.Next(0, 99);
					//Si l'attaquant gagne le tirage
                    Console.WriteLine("Tirage "+tirage);

					if(tirage >= 100 * chanceAtk)
					{
						unitDef._vie_restante --;
                        Console.WriteLine("Le defenseur perd une vie ");
					}
					else // C'est le defenseur qui a gagné le tirage
					{
						_vie_restante --;
                        Console.WriteLine("L'attaquant perd une vie ");
					}
				
					nbTour --;
				}
			
			//Si l'unité ne possède pas de defense ou plus de vie : on la tue !
			if(unitDef._vie_restante == 0 || unitDef._defense_base == 0)
			{
				unitDef.tuer();
                return 1;
			}
			
			//Si l'unité attaquante n'a plus de vie, l'attaque échoue et elle meurt
			if(_vie_restante == 0)
			{
				tuer();
                return 2;
			}

            return 3;
        }

    }
}